import datetime
import random
import re
import threading

from flask import request, current_app, abort, make_response, send_file, jsonify, session
from six import BytesIO
from info import redis_store, constants, db
from info.models import User
from info.utils.captcha.captcha import captcha

from info.utils.yuntongxun.sms import CCP
from . import passport_blu
import os
import logging

# Todo 实现图片验证码
@passport_blu.route('/image_code')
def get_image_code():
    '''
    生成图片验证码
    :return:
    '''
    # 1. 获取参数
    # 获取前端传来的图片uid
    image_Code = request.args.get("image_Code")
    # 2. 校验参数
    # 如果前端没有传来指定的image_Code,则返回错误验证码
    if not image_Code:
        f = open(os.path.join(constants.STATICFLODER, "wrongyz.gif"), "rb")
        data = f.read()
        f.close()
        logging.warning("用户使用不规范,没有传递对应参数")
        return make_response(send_file(BytesIO(data), attachment_filename="wrongyz.gif", mimetype="image/gif"), constants.PAGE_NOTFIND_TAG)
    # 3. 生成图片验证码
    # 使用工具获取对应的图片验证码
    cid,text,img = captcha.generate_captcha()
    # 4. 保存图片验证码
    # 将图片保存到redis中,若出错则返回错误验证码
    try:
        redis_store.set(image_Code,text)
        redis_store.expire(image_Code,constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        f = open(os.path.join(constants.STATICFLODER,"wrongyz.gif"),"rb")
        data = f.read()
        f.close()
        logging.error("系统出错,错误原因:%s"%e)
        return make_response(send_file(BytesIO(data),attachment_filename="wrongyz.gif",mimetype="image/gif"),constants.SYSTEM_WRONE_TAG)
    # 5.返回图片验证码
    return make_response(send_file(BytesIO(img),attachment_filename=cid+".png",mimetype="image/png"),constants.PAGE_NET_TAG)

# Todo 实现短信验证码
@passport_blu.route('/sms_code', methods=["POST"])
def send_sms_code():
    """
    发送短信的逻辑
    :return:
    """
    data = {}
    # 1.将前端参数转为字典
    mobile = request.json.get("mobile")
    image_code = request.json.get("image_code")
    image_code_id = request.json.get("image_code_id")
    # 2. 校验参数(参数是否符合规则，判断是否有值)
    if not all([mobile,image_code,image_code_id]):
        data["errno"] = constants.WRONG_INPUT_TAG
        data["errmsg"] = "参数不完整"
        return jsonify(data)
    pattern = re.compile("1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}")
    if not re.match(pattern,mobile):
        data["errno"] = constants.WRONG_INPUT_TAG
        data["errmsg"] = "手机号不符合规范"
        return jsonify(data)
    try:
        user = User.query.filter(User.mobile==mobile).all()
        if user:
            data["errno"] = constants.WRONG_INPUT_TAG
            data["errmsg"] = "手机号已被注册"
            return jsonify(data)
    except Exception as e:
        logging.error("Mysql数据库出现异常,异常原因:%s"%e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "系统异常"
        return jsonify(data)
    # 判断参数是否有值
    # 3. 先从redis中取出真实的验证码内容
    try:
        img_code = redis_store.get(image_code_id)
    except Exception as e:
        logging.error("Redis数据库出错,出错原因:%s" % e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "Redis数据库未开启"
        return jsonify(data)
    # 4. 与用户的验证码内容进行对比，如果对比不一致，那么返回验证码输入错误
    if img_code.lower() != image_code.lower():
        data["errno"] = constants.WRONG_INPUT_TAG
        data["errmsg"] = "验证码错误"
        return jsonify(data)
    # 5. 如果一致，生成短信验证码的内容(随机数据)
    # 或取对应的验证码
    yzm = "%6d"%random.randint(0,999999)
    # 6. 发送短信验证码
    try:
        # logging.debug("验证码为:%s"%yzm)
        t1 = threading.Thread(
            name="t1",
            target=CCP().send_template_sms,
            kwargs={
                "to":mobile,
                "datas":[yzm,5],
                "temp_id":1
            }
        )
        t1.start()
    except Exception as e:
        logging.error("云端出错,错误原因为:%s"%e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "短信云平台连接失败"
        return jsonify(data)
    # 保存验证码内容到redis
    try:
        redis_store.set(mobile,yzm)
        redis_store.expire(mobile,constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        logging.error("Redis数据库出错,出错原因:%s"%e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "Redis数据库未开启"
        return jsonify(data)
    # 7. 告知发送结果
    data["errno"] = constants.CORRECT_TAG
    return jsonify(data)

# Todo 实现注册功能
@passport_blu.route('/register', methods=["POST"])
def register():
    """
    注册功能
    :return:
    """
    data = {}
    # 1. 获取参数和判断是否有值
    mobile = request.json.get('mobile')
    smscode = request.json.get('smscode')
    password = request.json.get('password')
    if not all([mobile,smscode,password]):
        data["errno"] = constants.WRONG_INPUT_TAG
        data["errmsg"] = "参数不完整"
        return jsonify(data)
    try:
        user = User.query.filter(User.mobile==mobile).all()
        if user:
            data["errno"] = constants.WRONG_INPUT_TAG
            data["errmsg"] = "手机号已被注册"
            return jsonify(data)
    except Exception as e:
        logging.error("Mysql数据库出现异常,异常原因:%s"%e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "系统异常"
        return jsonify(data)
    # 2. 从redis中获取指定手机号对应的短信验证码的
    try:
        smcode = redis_store.get(mobile)
    except Exception as e:
        logging.error("Redis数据库出错,出错原因:%s"%e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "服务器出错"
        return jsonify(data)
    # 3. 校验验证码
    if smcode != smscode:
        logging.warning("验证码不正确")
        data["errno"] = 4004
        data["errmsg"] = "手机验证码不正确"
        return jsonify(data)
    # 4. 初始化 user 模型，并设置数据并添加到数据库
    try:
        # 初始化空的user对象,并添加对应参数
        user = User()
        user.password = password
        user.nick_name = mobile
        user.mobile = mobile
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        logging.error("Mysql数据库出错,出错原因:%s" % e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "服务器出错"
        return jsonify(data)
    # 5. 保存用户登录状态
    try:
        session["user_id"] = user.id
    except Exception as e:
        logging.error("Redis数据库出错,出错原因:%s" % e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "服务器出错"
        return jsonify(data)
    # 6. 返回注册结果
    data["errno"] = constants.CORRECT_TAG
    data["errmsg"] = "%s注册成功"%user.nick_name
    return jsonify(data)

# Todo 实现用户登录功能
@passport_blu.route('/login', methods=["POST"])
def login():
    """
    登陆功能
    :return:
    """
    data = {}
    # 1. 获取参数和判断是否有值
    mobile = request.json.get("mobile")
    password = request.json.get("password")
    if not all([mobile,password]):
        data["errno"] = constants.WRONG_INPUT_TAG
        data["errmsg"] = "参数不完整"
        return jsonify(data)
    # 2. 从数据库查询出指定的用户
    try:
        user = User.query.filter_by(mobile=mobile).all()
        if not user:
            data["errno"] = constants.WRONG_INPUT_TAG
            data["errmsg"] = "用户名不存在"
            return jsonify(data)
        user = user[0]
    except Exception as e:
        logging.error("Mysql服务器出错,错误原因%s"%e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "系统出错"
        return jsonify(data)
    # 3. 校验密码
    if not user.check_password(password):
        logging.warning("密码错误")
        data["errno"] = constants.WRONG_INPUT_TAG
        data["errmsg"] = "密码错误"
        return jsonify(data)
    # 4. 保存用户登录状态
    try:
        session["user_id"]=user.id
    except Exception as e:
        logging.error("Redis服务器出错,错误原因%s" % e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "系统出错"
        return jsonify(data)
    user.last_login = datetime.datetime.now()
    try:
        db.session.commit()
    except Exception as e:
        logging.error("Mysql服务器出错,错误原因%s" % e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "系统出错"
        return jsonify(data)
    # 5. 登录成功返回
    logging.info("欢迎%s登录本平台"%user.nick_name)
    data["errno"] = constants.CORRECT_TAG
    data["errmsg"] = "欢迎%s登录本平台"

    return jsonify(data)

# Todo 登出功能
@passport_blu.route("/logout", methods=['POST'])
def logout():
    """
    清除session中的对应登录之后保存的信息
    :return:
    """
    # 返回结果
    data = {}
    try:
        session.pop("user_id")
    except Exception as e:
        logging.error("Redis服务器出错,出错原因%s"%e)
        data["errno"] = constants.SYSTEM_WRONE_TAG
        data["errmsg"] = "系统出错"
        return jsonify(data)
    data["errno"] = constants.CORRECT_TAG
    return jsonify(data)